package chapter_15;

// java.util 第1部分：类集框架

/*
java.util中包含的类如下。在Java 2中新增加的一些也被列出：
AbstractCollection (Java 2) EventObject Random
AbstractList (Java 2) GregorianCalendar ResourceBundle
AbstractMap (Java 2) HashMap (Java 2) SimpleTimeZone
AbstractSequentialList (Java 2) HashSet (Java 2) Stack
AbstractSet (Java 2) Hashtable StringTokenizer
ArrayList (Java 2) LinkedList (Java 2) Timer (Java 2, v1.3)
Arrays (Java 2) ListResourceBundle TimerTask (Java 2, v1.3)
BitSet Locale TimeZone
Calendar Observable TreeMap (Java 2)
Collections (Java 2) Properties TreeSet (Java 2)
Date PropertyPermission (Java 2) Vector
Dictionary PropertyResourceBundle WeakHashMap (Java 2)
java.util定义了如下的接口。注意其中大多数是在Java 2中新增加的。
Collection (Java 2) List (Java 2) Observer
Comparator (Java 2) ListIterator (Java 2) Set (Java 2)
Enumeration Map (Java 2) SortedMap (Java 2)
EventListener Map.Entry (Java 2) SortedSet (Java 2)
Iterator (Java 2)
 */


/*
15.1 类集概述
在C++中叫做容器（container），而在Java中叫做类集。
 */


/*
15.2 类集接口
首先讨论类集接口是因为它们决定了collection类的基本特性。不同的是，具体类仅仅是
提供了标准接口的不同实现。支持类集的接口总结在如下的表中：
Collection 能使你操作对象组，它位于类集层次结构的顶层
List 扩展Collection去处理序列（对象的列表）
Set 扩展Collection去处理集合，集合必须包含唯一元素
SortedSet 扩展Set去处理排序集合

除了类集接口之外，类集也使用Comparator，Iterator和ListIterator接口。关于这些接口
将在本章后面做更深入的描述。简单地说，Comparator接口定义了两个对象如何比较；
Iterator和ListIterator接口枚举类集中的对象。
为了在它们的使用中提供最大的灵活性，类集接口允许对一些方法进行选择。可选择
的方法使得使用者可以更改类集的内容。支持这些方法的类集被称为可修改的
（modifiable）。不允许修改其内容的类集被称为不可修改的（unmodifiable）。如果对一
个不可修改的类集使用这些方法，将引发一个UnsupportedOperationException异常。所有内
置的类集都是可修改的。

    15.2.1 类集接口
    Collection接口是构造类集框架的基础。它声明所有类集都将拥有的核心方法。这些方
    法被总结在下表中。因为所有类集实现Collection，所以熟悉它的方法对于清楚地理解框
    架是必要的。其中几种方法可能会引发一个UnsupportedOperationException异常。正如上面
    解释的那样，这些发生在当类集不能被修改时。当一个对象与另一个对象不兼容，例如当
    企图增加一个不兼容的对象到一个类集中时。将产生一个ClassCastException异常。

    15.2.2 List接口
    List接口扩展了Collection并声明存储一系列元素的类集的特性。使用一个基于零的下
    标，元素可以通过它们在列表中的位置被插入和访问。一个列表可以包含复制元素。
    除了由Collection定义的方法之外，List还定义了一些它自己的方法，这些方法总结在
    下表中。再次注意当类集不能被修改时，其中的几种方法引发UnsupportedOperation
    Exception异常。当一个对象与另一个不兼容，例如当企图将一个不兼容的对象加入一个类
    集中时，将产生ClassCastException异常。

    15.2.3 集合接口
    集合接口定义了一个集合。它扩展了Collection并说明了不允许复制元素的类集的特
    性。因此，如果试图将复制元素加到集合中时，add( )方法将返回false。它本身并没有定义
    任何附加的方法。

    15.2.4 SortedSet接口
    SortedSet接口扩展了Set并说明了按升序排列的集合的特性。除了那些由Set定义的方法
    之外，由SortedSet接口说明的方法列在下表中。当没有项包含在调用集合中时，其中的
    几种方法引发NoSuchElementException异常。当对象与调用集合中的元素不兼容时，引发
    ClassCastException 异常。如果试图使用null 对象， 而集合不允许null 时， 引发
    NullPointerException异常。
 */


/*
15.3 Collection类
标准的Collection类总结在下面的表中。
AbstractCollection  实现大多数Collection接口
AbstractList        扩展AbstractCollection并实现大多数List接口
AbstractSequentialList 为了被类集使用而扩展AbstractList，该类集使用连续而不是随机方
式访问其元素
LinkedList          通过扩展AbstractSequentialList来实现链接表
ArrayList           通过扩展AbstractList来实现动态数组
AbstractSet         扩展AbstractCollection并实现大多数Set接口
HashSet             为了使用散列表而扩展AbstractSet
TreeSet             实现存储在树中的一个集合。扩展AbstractSet
注意：除了Collection类外，还有几个从以前版本遗留下来的类，如Vector，Stack
和Hashtable均被重新设计成支持类集的形式。
    15.3.1 ArrayList类
    ArrayList类扩展AbstractList并执行List接口。ArrayList支持可随需要而增长的动态数
    组。在Java中，标准数组是定长的。在数组创建之后，它们不能被加长或缩短，这也就意
    味着你必须事先知道数组可以容纳多少元素。但是，你直到运行时才能知道需要多大的数
    组。为了解决这个问题，类集框架定义了ArrayList。本质上，ArrayList是对象引用的一个
    变长数组。也就是说，ArrayList能够动态地增加或减小其大小。数组列表以一个原始大小
    被创建。当超过了它的大小，类集自动增大。当对象被删除后，数组就可以缩小。
    注意：动态数组也被从以前版本遗留下来的类Vector所支持。
    ArrayList有如下的构造函数：
    ArrayList( )
    ArrayList(Collection c)
    ArrayList(int capacity)
    其中第一个构造函数建立一个空的数组列表。第二个构造函数建立一个数组列表，该
    数组列表由类集c中的元素初始化。第三个构造函数建立一个数组列表，该数组有指定的初
    始容量（capacity）。容量是用于存储元素的基本数组的大小。当元素被追加到数组列表上
    时，容量会自动增加。

    从数组列表（ArrayList）获得数组（Array）
    当使用ArrayList时，有时想要获得一个实际的数组，这个数组包含了列表的内容。正
    如前面解释的那样，可以通过调用方法toArray( )来实现它。下面是几个为什么可能想将类
    集转换成为数组的原因：
    · 对于特定的操作，可以获得更快的处理时间。
    · 为了给方法传递数组，而方法不必重载去接收类集。
    · 为了将新的基于类集的程序与不认识类集的老程序集成。

    15.3.2 LinkedList类
    LinkedList类扩展AbstractSequentialList并执行List接口。它提供了一个链接列表数据结
    构。它具有如下的两个构造函数，说明如下：
    LinkedList( )
    LinkedList(Collection c)
    第一个构造函数建立一个空的链接列表。第二个构造函数建立一个链接列表，该链接
    列表由类集c中的元素初始化。
    除了它继承的方法之外，LinkedList类本身还定义了一些有用的方法，这些方法主要用
    于操作和访问列表。使用addFirst( )方法可以在列表头增加元素；使用addLast( )方法可以在
    列表的尾部增加元素。它们的形式如下所示：
    void addFirst(Object obj)
    void addLast(Object obj)
    这里，obj是被增加的项。
    调用getFirst( )方法可以获得第一个元素。调用getLast( )方法可以得到最后一个元素。
    它们的形式如下所示：
    Object getFirst( )
    Object getLast( )
    为了删除第一个元素，可以使用removeFirst( )方法；为了删除最后一个元素，可以调
    用removeLast( )方法。它们的形式如下所示：
    Object removeFirst( )
    Object removeLast( )

    15.3.3 HashSet类
    HashSet扩展AbstractSet并且实现Set接口。它创建一个类集，该类集使用散列表进行存
    储。在散列（hashing）中，一个关键字的信息内容被用来确定唯一的一个值，称为散列码。
    而散列码被用来当做与关键字相连的数据的存储下标。关键字到其散列码的转换
    是自动执行的——你看不到散列码本身。你的程序代码也不能直接索引散列表。散列法的
    优点在于即使对于大的集合，它允许一些基本操作如add( )，contains( )，remove( )和size( )
    方法的运行时间保持不变。
    下面的构造函数定义为：
    HashSet( )
    HashSet(Collection c)
    HashSet(int capacity)
    HashSet(int capacity, float fillRatio)
    第一种形式构造一个默认的散列集合。第二种形式用c中的元素初始化散列集合。第三
    种形式用capacity初始化散列集合的容量。第四种形式用它的参数初始化散列集合的容量和
    填充比（也称为加载容量）。填充比必须介于0.0与1.0之间，它决定在散列集合向上调整大
    小之前，有多少能被充满。具体的说，就是当元素的个数大于散列集合容量乘以它的填充
    比时，散列集合被扩大。对于没有获得填充比的构造函数，默认使用0.75。
    HashSet没有定义任何超过它的超类和接口提供的其他方法。
    重要的是，注意散列集合并没有确保其元素的顺序，因为散列法的处理通常不让自己
    参与创建排序集合。如果需要排序存储，另一种类集——TreeSet将是一个更好的选择。
    备注：实际打印出来HashSet也是排好序的。

    15.3.4 TreeSet类
    TreeSet为使用树来进行存储的Set接口提供了一个工具，对象按升序存储。访问和检索
    是很快的。在存储了大量的需要进行快速检索的排序信息的情况下，TreeSet是一个很好的
    选择。
    下面的构造函数定义为：
    TreeSet( )
    TreeSet(Collection c)
    TreeSet(Comparator comp)
    TreeSet(SortedSet ss)
    第一种形式构造一个空的树集合，该树集合将根据其元素的自然顺序按升序排序。第
    二种形式构造一个包含了c的元素的树集合。第三种形式构造一个空的树集合，它按照由
    comp指定的比较函数进行排序（比较函数将在本章后面介绍）。第四种形式构造一个包含
    了ss的元素的树集合
 */


/*
15.4 通过迭代函数访问类集
通常希望循环通过类集中的元素。例如，可能会希望显示每一个元素。到目前为止，
处理这个问题的最简单方法是使用iterator，iterator是一个或者实现Iterator或者实现
ListIterator接口的对象。Iterator可以完成循环通过类集，从而获得或删除元素。ListIterator
扩展Iterator，允许双向遍历列表，并可以修改单元。
    15.4.1 使用迭代函数
    在通过迭代函数访问类集之前，必须得到一个迭代函数。每一个Collection类都提供一
    个iterator( )函数，该函数返回一个对类集头的迭代函数。通过使用这个迭代函数对象，可
    以访问类集中的每一个元素，一次一个元素。通常，使用迭代函数循环通过类集的内容，
    步骤如下：
    1. 通过调用类集的iterator( )方法获得对类集头的迭代函数。
    2. 建立一个调用hasNext( )方法的循环，只要hasNext( )返回true，就进行循环迭代。
    3. 在循环内部，通过调用next( )方法来得到每一个元素。
    对于执行List的类集，也可以通过调用ListIterator来获得迭代函数。正如上面解释的那
    样，列表迭代函数提供了前向或后向访问类集的能力，并可让你修改元素。否则，ListIterator
    如同Iterator功能一样。
 */


/*
15.5 将用户定义的类存储于Collection中
类集的能力是它能存储任何类型的对象，包括你所创建的类的对象。
 */


/*
15.6 处理映射
映射（map）是一个存储关键字和值的关联或者说是关键字/值对的对象。给定一个关键字，
可以得到它的值。关键字和值都是对象。关键字必须是唯一的。但值是可以被复制的。有些
映射可以接收null关键字和null值。而有的则不行。

    15.6.1 映射接口
    因为映射接口定义了映射的特征和本质，因此关于映射的讨论从这里开始。下面的接
    口支持映射：
    接口              描述
    Map             映射唯一关键字给值
    Map.Entry       描述映射中的元素（关键字/值对）。这是Map的一个内部类
    SortedMap       扩展Map以便关键字按升序保持

    Map 接口
    Map接口映射唯一关键字到值。关键字（key）是以后用于检索值的对象。给定一个关
    键字和一个值，可以存储这个值到一个Map对象中。当这个值被存储以后，就可以使用它
    的关键字来检索它。当调用的映射中没有项存在时，其中的几种方法会引发一个
    NoSuchElementException异常。而当对象与映射中的元素不兼容时，引发一个
    ClassCastException异常。如果试图使用映射不允许使用的null对象时，则引发
    一个NullPointerException异常。当试图改变一个不允许修改的映射时，则引发一个
    UnsupportedOperationException异常。

    映射循环使用两个基本操作：get( )和put( )。使用put( )方法可以将一个指定了关键字和
    值的值加入映射。为了得到值，可以通过将关键字作为参数来调用get( )方法。调用返回该
    值。
    正如前面谈到的，映射不是类集，但可以获得映射的类集“视图”。为了实现这种功
    能，可以使用entrySet( )方法，它返回一个包含了映射中元素的集合（Set）。为了得到关键
    字的类集“视图”，可以使用keySet( )方法。为了得到值的类集“视图”，可以使用values( )
    方法。类集“视图”是将映射集成到类集框架内的手段。

    SortedMap 接口
    SortedMap接口扩展了Map，它确保了各项按关键字升序排序。
    当调用映射中没有的项时，其中的几种方法引发一个NoSuchElement
    Exception异常。当对象与映射中的元素不兼容时，则引发一个ClassCastException异常。当
    试图使用映射不允许使用的null对象时，则引发一个NullPointerException异常。
    排序映射允许对子映射（换句话说，就是映射的子集）进行高效的处理。使用
    headMap( )，tailMap( )或subMap( )方法可以获得子映射。调用firstKey( )方法可以获得集合
    的第一个关键字。而调用lastKey( )方法可以获得集合的最后一个关键字。

    Map.Entry 接口
    Map.Entry接口使得可以操作映射的输入。回想由Map接口说明的entrySet( )方法，调用
    该方法返回一个包含映射输入的集合（Set）。这些集合元素的每一个都是一个Map.Entry
    对象。
    boolean equals(Object obj) 如果obj是一个关键字和值都与调用对象相等的Map.Entry，则返回true
    Object getKey( )            返回该映射项的关键字
    Object getValue( )          返回该映射项的值
    int hashCode( )             返回该映射项的散列值
    Object setValue(Object v)   将这个映射输入的值赋给v。

    15.6.2 映射类
    有几个类提供了映射接口的实现。可以被用做映射的类总结如下：
    类               描述
    AbstractMap     实现大多数的Map接口
    HashMap         将AbstractMap扩展到使用散列表
    TreeMap         将AbstractMap扩展到使用树
    WeakHashMap     将AbstractMap扩展到使用弱关键字散列表
    注意AbstractMap对三个具体的映射实现来说，是一个超类。WeakHashMap实现一个使
    用“弱关键字”的映射，它允许映射中的元素，当该映射的关键字不再被使用时，被放入
    回收站。关于这个类，在这里不做更深入的讨论。其他的类将在下面介绍。

    HashMap 类
    HashMap类使用散列表实现Map接口。这允许一些基本操作如get( )和put( )的运行时间
    保持恒定，即便对大型集合，也是这样的。
    下面的构造函数定义为：
    HashMap( )
    HashMap(Map m)
    HashMap(int capacity)
    HashMap(int capacity, float fillRatio)
    第一种形式构造一个默认的散列映射。第二种形式用m的元素初始化散列映射。第三
    种形式将散列映射的容量初始化为capacity。第四种形式用它的参数同时初始化散列映射的
    容量和填充比。容量和填充比的含义与前面介绍的HashSet中的容量和填充比相同。
    HashMap实现Map并扩展AbstractMap。它本身并没有增加任何新的方法。

    TreeMap 类
    TreeMap类通过使用树实现Map接口。TreeMap提供了按排序顺序存储关键字/值对的有
    效手段，同时允许快速检索。应该注意的是，不像散列映射，树映射保证它的元素按照关
    键字升序排序。
    下面的TreeMap构造函数定义为：
    TreeMap( )
    TreeMap(Comparator comp)
    TreeMap(Map m)
    TreeMap(SortedMap sm)
    第一种形式构造一个空树的映射，该映射使用其关键字的自然顺序来排序。第二种形
    式构造一个空的基于树的映射，该映射通过使用Comparator comp来排序（比较函数
    Comparators将在本章后面进行讨论）。第三种形式用从m的输入初始化树映射，该映射使
    用关键字的自然顺序来排序。第四种形式用从sm的输入来初始化一个树映射，该映射将按
    与sm相同的顺序来排序。
    TreeMap实现SortedMap并且扩展AbstractMap。而它本身并没有另外定义其他方法。
*/


/*
15.7 比较函数
TreeSet和TreeMap都按排序顺序存储元素。然而，精确定义采用何种“排序顺序”的
是比较函数。通常在默认的情况下，这些类通过使用被Java称之为“自然顺序”的顺序存
储它们的元素，而这种顺序通常也是你所需要的（A在B的前面，1在2的前面，等等）。如
果需要用不同的方法对元素进行排序，可以在构造集合或映射时，指定一个Comparator对
象。这样做为你提供了一种精确控制如何将元素储存到排序类集和映射中的能力。
Comparator接口定义了两个方法：compare( )和equals( )。这里给出的compare( )方法按
顺序比较了两个元素：
int compare(Object obj1, Object obj2)
obj1和obj2是被比较的两个对象。当两个对象相等时，该方法返回0；当obj1大于obj2
时，返回一个正值；否则，返回一个负值。如果用于比较的对象的类型不兼容的话，该方
法引发一个ClassCastException异常。通过覆盖compare( )，可以改变对象排序的方式。例如，
通过创建一个颠倒比较输出的比较函数，可以实现按逆向排序。
这里给出的equals( )方法，测试一个对象是否与调用比较函数相等：
boolean equals(Object obj)
obj是被用来进行相等测试的对象。如果obj和调用对象都是Comparator的对象并且使用
相同的排序。该方法返回true。否则返回false。重载equals( )方法是没有必要的，大多数简
单的比较函数都不这样做。
    15.7.1 使用比较函数
 */


/*
15.8 类集算法
类集框架定义了几种能用于类集和映射的算法。在Collections类中，这些算法被定义为
静态方法。当试图比较不兼容的类型时，其中的一些算法引发一个ClassCastException
异常； 而当试图改变一个不可改变的类集时， 则引发一个
UnsupportedOperationException异常。
在类集方法中，如synchronizedList( )和synchronizedSet( )被用来获得各种类集的
同步（安全线程）拷贝。正如前面解释的那样，没有任何一个标准类集实现是同步的。必
须使用同步算法来为其提供同步。另一种观点：同步类集的迭代函数必须在synchronized块
内使用。
以unmodifiable开头的一组方法返回不能被改变的各种类集“视图”。这些方法当将一
些进程对类集设为只读形式时很有用的。
Collections定义了三个静态变量：EMPTY_SET，EMPTY_LIST和EMPTY_MAP。它们
都是不可改变的。
 */


/*
15.9 Arrays（数组）
这个类提供了各种在进行数组运算时很有用的方法。尽管这些方法在技术上不属于类集框架，
但它们提供了跨越类集和数组的桥梁。在这一节中，分析由Arrays定义的每一种方法。
asList( )方法返回一个被指定数组支持的List。换句话说，列表和数组访问的是同一个
单元。它具有如下的形式：
static List asList(Object[ ] array)
这里array是包含了数据的数组。
binarySearch( )方法使用二进制搜索寻找指定的值。该方法必须应用于排序数组。它具
有如下的形式：
static int binarySearch(byte[ ] array, byte value)
static int binarySearch(char[ ] array, char value)
static int binarySearch(double[ ] array, double value)
static int binarySearch(float[ ] array, float value)
static int binarySearch(int[ ] array, int value)
static int binarySearch(long[ ] array, long value)
static int binarySearch(short[ ] array, short value)
static int binarySearch(Object[ ] array, Object value)
static int binarySearch(Object[ ] array, Object value, Comparator c)
 */


/*
15.10 从以前版本遗留下来的类和接口
由java.util定义的从以前版本遗留下来的类说明如下：
Dictionary  Hashtable   Properties  Stack   Vector

    15.10.1 Enumeration接口
    Enumeration接口定义了可以对一个对象的类集中的元素进行枚举（一次获得一个）的
    方法。这个接口尽管没有被摈弃，但已经被Iterator所替代。Enumeration对新程序来说是过
    时的。然而它仍被几种从以前版本遗留下来的类（例如Vector和Properties）所定义的方法
    使用，被几种其他的API类所使用以及被目前广泛使用的应用程序所使用。
    Enumeration指定下面的两个方法：
    boolean hasMoreElements( )
    Object nextElement( )

    15.10.2 Vector
    Vector实现动态数组。这与ArrayList相似，但两者不同的是：Vector是同步的，并且它
    包含了许多不属于类集框架的从以前版本遗留下来的方法。随着Java 2的公布，Vector被重
    新设计来扩展AbstractList和实现List接口，因此现在它与类集是完全兼容的。

    15.10.3 Stack
    Stack是Vector的一个子类，它实现标准的后进先出堆栈。Stack仅仅定义了创建空堆栈
    的默认构造函数。

    15.10.4 Dictionary
    字典（Dictionary）是一个表示关键字/值存储库的抽象类，同时它的操作也很像映射
    （Map）。给定一个关键字和值，可以将值存储到字典（Dictionary）对象中。一旦这个值
    被存储了，就能够用它的关键字来检索它。因此，与映射一样，字典可以被当做关键字/值
    对列表来考虑。尽管在Java 2中并没有摈弃字典（Dictionary），由于它被映射（Map）所取
    代，从而被认为是过时的。

    15.10.5 Hashtable
    散列表（Hashtable）是原始java.util中的一部分同时也是Dictionary的一个具体实现。然
    而，Java 2重新设计了散列表（Hashtable）以便它也能实现映射（Map）接口。因此现在
    Hashtable也被集成到类集框架中。它与HashMap相似，但它是同步的。

    15.10.6 Properties
    属性（Properties）是Hashtable的一个子类。它用来保持值的列表，在其中关键字和值
    都是字符串（String）。Properties类被许多其他的Java类所使用。例如，当获得系统环境值
    时，System.getProperties( )返回对象的类型。

    15.10.7 使用store( )和load( )
    Properties的一个最有用的方面是可以利用store( )和load( )方法方便地对包含在属性
    （Properties）对象中的信息进行存储或从盘中装入信息。在任何时候，都可以将一个属性
    （Properties）对象写入流或从中将其读出。这使得属性列表特别方便实现简单的数据库。
    例如，下面的程序使用属性列表创建一个简单的用计算机处理的存储着姓名和电话号码的
    电话本。为了寻找某人的电话号码，可输入他或者她的名字。程序使用store( )和load( )方法
    来存储和检索列表。当程序执行时，它首先试着从一个叫做phonebook.dat的文件中装入列
    表。如果这个文件存在，列表就被装入。然后就可以增加列表。如果这样做了，当终止程
    序时，新列表就会被保存。
 */



import java.util.*;


class ArrayListDemo {
    // 15.3.1
    static void runner() {
        // create an array list
        ArrayList al = new ArrayList();
        System.out.println("Initial size of al: " + al.size());

        // add elements to the array list
        al.add("C");
        al.add("A");
        al.add("E");
        al.add("B");
        al.add("D");
        al.add("F");
        al.add(1, "A2");
        System.out.println("Size of al after additions: " + al.size());

        // display the array list
        System.out.println("Contents of al:" + al);

        // Remove the array list
        al.remove("F");
        al.remove(2);

        System.out.println("Size of al after deletions: " + al.size());
        System.out.println("Contents of al: " + al);
        /*
        尽管当对象被存储在ArrayList对象中时，其容量会自动增加。仍可以通过调用
        ensureCapacity( )方法来人工地增加ArrayList的容量。如果事先知道将在当前能够容纳的类
        集中存储许许多多的项时，你可能会想这样做。在开始时，通过一次性地增加它的容量，
        就能避免后面的再分配。因为再分配是很花时间的，避免不必要的处理可以改善性能。
        ensureCapacity( )方法的特征如下所示：
        void ensureCapacity(int cap)
        这里，cap是新的容量。
        相反地，如果想要减小在ArrayList对象之下的数组的大小，以便它有正好容纳当前项
        的大小，可以调用trimToSize( )方法。该方法说明如下：
        void trimToSize( )
         */
    }
}


class ArrayListToArray {
    // 15.3.1
    public static void runner() {
        // Create an array list
        ArrayList al = new ArrayList();
        // Add elements to the array list
        al.add(new Integer(1));
        al.add(new Integer(2));
        al.add(new Integer(3));
        al.add(new Integer(4));
        System.out.println("Contents of al: " + al);
        // get array
        Object ia[] = al.toArray();
        int sum = 0;
        // sum the array
        for(int i=0; i<ia.length; i++)
            sum += ((Integer) ia[i]).intValue();
        System.out.println("Sum is: " + sum);
        /*
        程序开始时创建一个整数的类集。正如上面做出的解释那样，由于不能将原始类型存
        储在类集中，因此类型Integer的对象被创建并被保存。接下来，toArray( )方法被调用，它
        获得了一个Objects数组。这个数组的内容被置为整型（Integer），接下来对这些值进行求
        和。
         */
    }
}


class LinkedListDemo {
    // 15.3.2
    static void runner() {
        // create a linked list
        LinkedList ll = new LinkedList();

        // add elements to the linked list
        ll.add("F");
        ll.add("B");
        ll.add("D");
        ll.add("E");
        ll.add("C");
        ll.addLast("Z");
        ll.addFirst("A");
        ll.add(1, "A2");
        System.out.println("Original contents of ll: " + ll);

        // remove elements from the linked list
        ll.remove("F");
        ll.remove(2);
        System.out.println("Contents of ll after deletion: " + ll);

        // remove first and last elements
        ll.removeFirst();
        ll.removeLast();
        System.out.println("ll after deleting first and last: " + ll);

        // get and set a value
        Object val = ll.get(2);
        ll.set(2, (String) val + "Changed");
        System.out.println("ll after change: " + ll);
    }
}


class HashSetDemo {
    // 15.3.3
    static void runner() {
        // create a hash set
        HashSet hs = new HashSet();
        // add elements to the hash set
        hs.add("B");
        hs.add("A");
        hs.add("D");
        hs.add("E");
        hs.add("C");
        hs.add("F");
        System.out.println(hs);
    }
}


class TreeSetDemo {
    // 15.3.4
    public static void runner() {
        // Create a tree set
        TreeSet ts = new TreeSet();
        // Add elements to the tree set
        ts.add("C");
        ts.add("A");
        ts.add("B");
        ts.add("E");
        ts.add("F");
        ts.add("D");
        System.out.println(ts);
    }
}


class IteratorDemo {
    // 15.4.1
    static void runner() {
        // create an array list
        ArrayList al = new ArrayList();
        // add elements to the array list
        al.add("C");
        al.add("A");
        al.add("E");
        al.add("B");
        al.add("D");
        al.add("F");
        // use iterator to display contents of al
        System.out.print("Original contents of al: ");
        Iterator itr = al.iterator();
        while(itr.hasNext()) {
            Object element = itr.next();
            System.out.print(element + " ");
        }
        System.out.println();
        // modify objects being iterated
        ListIterator litr = al.listIterator();
        while(litr.hasNext()) {
            Object element = litr.next();
            litr.set(element + "+");
        }
        System.out.print("Modified contents of al: ");
        itr = al.iterator();
        while(itr.hasNext()) {
            Object element = itr.next();
            System.out.print(element + " ");
        }
        System.out.println();

        // now, display the list backwards
        System.out.print("Modified list backwards: ");
        while(litr.hasPrevious()) {
            Object element = litr.previous();
            System.out.print(element + " ");
        }
        System.out.println();
        /*
        这里是一个实现这些步骤的例子，说明了Iterator和ListIterator。它使用ArrayList对象，
        但是总的原则适用于任何类型的类集。当然，ListIterator只适用于那些实现List接口的类集。
         */
    }
}


class Address {
    // 15.5
    private String name;
    private String street;
    private String city;
    private String state;
    private String code;
    Address(String n, String s, String c,
            String st, String cd) {
        name = n;
        street = s;
        city = c;
        state = st;
        code = cd;
    }
    public String toString() {
        return name + "\n" + street + "\n" +
                city + " " + state + " " + code;
    }

    static void runner() {
        LinkedList ml = new LinkedList();
        // add elements to the linked list
        ml.add(new Address("J.W. West", "11 Oak Ave",
                "Urbana", "IL", "61801"));
        ml.add(new Address("Ralph Baker", "1142 Maple Lane",
                "Mahomet", "IL", "61853"));
        ml.add(new Address("Tom Carlton", "867 Elm St",
                "Champaign", "IL", "61820"));
        Iterator itr = ml.iterator();
        while (itr.hasNext()) {
            Object element = itr.next();
            System.out.println(element + "\n");
        }
        System.out.println();
    }
}


class HashMapDemo {
    // 15.6.2 HashMap
    static void runner() {
        // create a hash map
        HashMap hm = new HashMap();

        // put elements to the map
        hm.put("John Doe", new Double(3434.34));
        hm.put("Tom Smith", new Double(123.22));
        hm.put("Jane Baker", new Double(1378.00));
        hm.put("Todd Hall", new Double(99.22));
        hm.put("Ralph Smith", new Double(-19.08));

        // get a set of the entries
        Set set = hm.entrySet();

        // get an iterator
        Iterator i = set.iterator();

        // display elements
        while (i.hasNext()) {
            Map.Entry me = (Map.Entry) i.next();
            System.out.print(me.getKey() + ": ");
            System.out.println(me.getValue());
        }
        System.out.println();

        // Deposit 1000 into John Doe's account
        double balance = ((Double) hm.get("John Doe")).doubleValue();
        hm.put("John Doe", new Double(balance + 1000));
        System.out.println("John Doe's new balance: " + hm.get("John Doe"));
        /*
        程序开始创建一个散列映射，然后将名字的映射增加到平衡表中。接下来，映射的内
        容通过使用由调用函数entrySet( )而获得的集合“视图”而显示出来。关键字和值通过调用
        由Map.Entry定义的getKey( )和getValue( )方法而显示。
         */
    }
}


class TreeMapDemo {
    // 15.6.2 TreeMap
    static void runner() {
        // Create a tree map
        TreeMap tm = new TreeMap();
        // Put elements to the map
        tm.put("John Doe", new Double(3434.34));
        tm.put("Tom Smith", new Double(123.22));
        tm.put("Jane Baker", new Double(1378.00));
        tm.put("Todd Hall", new Double(99.22));
        tm.put("Ralph Smith", new Double(-19.08));
        // Get a set of the entries
        Set set = tm.entrySet();
        // Get an iterator
        Iterator i = set.iterator();
        // Display elements
        while(i.hasNext()) {
            Map.Entry me = (Map.Entry)i.next();
            System.out.print(me.getKey() + ": ");
            System.out.println(me.getValue());
        }
        System.out.println();
        // Deposit 1000 into John Doe's account
        double balance = ((Double)tm.get("John Doe")).doubleValue();
        tm.put("John Doe", new Double(balance + 1000));
        System.out.println("John Doe's new balance: " +
                tm.get("John Doe"));
    }
}


class MyComp implements Comparator {
    // 15.7.1

    public int compare(Object a, Object b) {
        String aStr, bStr;

        aStr = a.toString();
        bStr = b.toString();

        // reverse the comparison
        return bStr.compareTo(aStr);
    }

    static void runner () {
        // Create a tree set
        TreeSet ts = new TreeSet(new MyComp());
        // Add elements to the tree set
        ts.add("C");
        ts.add("A");
        ts.add("B");
        ts.add("E");
        ts.add("F");
        ts.add("D");
        // Get an iterator
        Iterator i = ts.iterator();
        // Display elements
        while(i.hasNext()) {
            Object element = i.next();
            System.out.print(element + " ");
        }
        System.out.println();
        /*
        仔细观察实现Comparator并覆盖compare( )方法的MyComp类（正如前面所解释的那样，
        覆盖equals( )方法既不是必须的，也不是常用的）。在compare( )方法内部，String方法
        compareTo( )比较两个字符串。然而由bStr——不是aStr——调用compareTo( )方法，这导致
        比较的结果被逆向。
         */
    }
}

public class chapter_15 {

    public static void main(String[] args) {
        // 15.3.1
//        ArrayListDemo.runner();
//        ArrayListToArray.runner();

        //15.3.2
//        LinkedListDemo.runner();
        // 15.3.3
//        HashSetDemo.runner();
        // 15.3.4
//        TreeSetDemo.runner();
        // 15.4.1
//        IteratorDemo.runner();
        // 15.5
//        Address.runner();
        // 15.6.2 HashMap
//        HashMapDemo.runner();
        // 15.6.2 TreeMap
//        TreeMapDemo.runner();
        // 15.7.1
        MyComp.runner();
    }
}
